import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.utils import shuffle


def generate(sample_size, mean, cov, diff, regression):
    num_classes = 2
    sample_per_class = int(sample_size / num_classes)

    x0 = np.random.multivariate_normal(mean, cov, sample_per_class)
    y0 = np.zeros(sample_per_class)

    for ci, d in enumerate(diff):
        x1 = np.random.multivariate_normal(mean + d, cov, sample_per_class)
        y1 = (ci + 1) * np.ones(sample_per_class)

        x0 = np.concatenate((x0, x1))
        y0 = np.concatenate((y0, y1))
    # print(x0[:20], y0[:20])
    x, y = shuffle(x0, y0)
    # print(x[:20], y[:20])
    return x, y


np.random.seed(10)
num_class = 2
mean = np.random.randn(num_class)
cov = np.eye(num_class)
x, y = generate(1000, mean, cov, [3.], None)

colors = ['r' if num == 0 else 'b' for num in y[:]]
plt.scatter(x[:, 0], x[:, 1], c=colors)
plt.xlabel('Scaled age (in years)')
plt.ylabel('Tumor size (in cm)')
plt.show()

input_dim = 2
lab_dim = 1
input_features = tf.placeholder(tf.float64, [None, input_dim])
input_labels = tf.placeholder(tf.float64, [None, lab_dim])
# 定义学习参数
weights = tf.Variable(tf.random_normal([input_dim, lab_dim], dtype=tf.float64), name='weights')
biases = tf.Variable(np.zeros([lab_dim]), name='biases')

output = tf.nn.sigmoid(tf.matmul(input_features, weights) + biases)
# 损失函数  交叉熵方式
cross_entropy = -(input_labels*tf.log(output)+(1-input_labels)*tf.log(1-output))
loss = tf.reduce_mean(cross_entropy)

ser = tf.square(input_labels - output)
err = tf.reduce_mean(ser)

optimizer = tf.train.AdamOptimizer(0.04)
train = optimizer.minimize(loss)

max_epoch = 50
mini_batch_size = 25

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    for epoch in range(max_epoch):
        sum_err = 0
        for i in range(np.int32(len(y)/mini_batch_size)):
            x1 = x[i*mini_batch_size:(i+1)*mini_batch_size, :]
            y1 = np.reshape(y[i*mini_batch_size:(i+1)*mini_batch_size], [-1, 1])
            tf.reshape(y1, [-1, 1])
            _, loss_val, output_val, err_val = sess.run([train, loss, output, err],
                                                        feed_dict={input_features: x1, input_labels: y1})
            sum_err = sum_err + err_val
        print('Epoch: ', '%04d' % (epoch+1), 'cost: ', '{:.9f}'.format(loss_val), 'err: ', sum_err/mini_batch_size)

    train_x, train_y = generate(100, mean, cov, [3.], None)
    colors = ['r' if num == 0 else 'b' for num in train_y[:]]
    plt.scatter(train_x[:, 0], train_x[:, 1], c=colors)
    x = np.linspace(-1, 8, 200)
    """
    模型的生成z的公式可以表示为 z=x1*w1+x2*w2+b, 如果将 x1 和 x2 映射到直角坐标系中的 x 和 y 坐标，那么 z 就可以
    被分为小于0和大于0的两部分。当 z=0 时，就代表直线本身，另 z=0，化简： x2 = x1*w1/w2-b/w2, 即， y = x*(w1/w2)-(b/w2)
    """
    y = -x*(sess.run(weights)[0]/sess.run(weights)[1])-sess.run(biases)/sess.run(weights)[1]
    plt.plot(x, y)
    plt.legend('Fitted line')
    plt.show()

